﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Timers;
using Snake.Model;
using Snake.Vue;
using System.Threading;

namespace Snake
{
    public partial class MainVue : Form
    {

        public int count;

        private int tailleAncienSnake=4;
        private Boolean FinPartie=true;

        private Boolean move = false;


        private Mutex mut = new Mutex();
        private System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
        private Label label = new Label();
        private snake snake = new snake();
        private snake snakeRecu = new snake();
        private Pomme pomme = new Pomme();
        private Bonus bonus = new Bonus();
        private string Ip = "127.0.0.1";
        private string chemin = Environment.CurrentDirectory;
        private Bonus bobonus = new Bonus();
        private string NomJoueur;
        private string type;
        private Connexion connexion;
        private Perdu FenetrePerdu;
        private List<PictureBox> pictureList;
        private List<PictureBox> pictureList_other_player;
        private bool BonusOuPas = false;
        private int score = 0;
        private Boolean JeuxFin;

        public string ip
        {
            set { this.Ip = value; }
        }

        public String Type
        {
            get { return this.type; }
            set { this.type = value; }
        }


        
        public MainVue()
        {
            InitializeComponent();

            //Premier affichage - probleme du coup avec la fonction d'affichage qui utilise ces donnée, le snake
            //de l'autre joueur ne posséde pas les même donnée obligatoirement.
            //On cree la liste des pictures box affichées a l'écran

            this.pictureList = new List<PictureBox>();
            this.pictureList_other_player = new List<PictureBox>();

            this.initialisation_snake(this.snake,false);
            //this.initialisation_snake(this.snakeRecu, true);
          
            this.pomme = new Pomme();
            //AFFICHAGE DE LA POMME
            this.EcranPrincipal.Controls.Add(this.pomme.Pictures);
            this.Monscore.Text = "Votre score : " + (this.score);

            this.timer.Tick += new EventHandler(gameLoop); // Everytime timer ticks, timer_Tick will be called
            this.timer.Interval = (100);              // Timer will tick evert second : 100ms pour un oeil humain pas $etre malade affichage
            this.timer.Enabled = true;                       // Enable the timer
                                          // Start the timer
          
            this.timer.Start();                                         //il faut un timer "JEUX" et un timer"Affichage"
            
           
        }
        /*
         * Fonction d'initialisation : 1er argument snake à init pour affichage, 2éme argument si recu ( true ) sinon false
         * 
         */
        private void initialisation_snake(snake snake,Boolean recu)
        {
            int count = 1;
            foreach (Point point in snake.Cords)
            {
                PictureBox picture = new PictureBox();
                picture.SetBounds(snake.Cords.ElementAt(count - 1).X, snake.Cords.ElementAt(count - 1).Y, 10, 10);
                picture.Visible = true;

                if (count == this.snake.Size)
                {
                    picture.Load("./../../Ressource/Tetedroite.png");
                }
                else
                {
                    picture.Load("./../../Ressource/Corps.png");
                }

                if (!recu)
                {
                    this.EcranPrincipal.Controls.Add(picture);
                    this.pictureList.Add(picture);
                }
                else
                {
                    this.Ecransecond.Controls.Add(picture);
                    this.pictureList_other_player.Add(picture);
                }
                //snake.ReturnList.Add(picture);
                count++;
            }
        }


        void gameLoop(object sender, EventArgs e)
        {
            this.snake.Envoyer = false;
            this.move = false;

            if (panel2.Visible == true)
            {
               
                if (this.type == "Serveur")
                {
                    this.JoueurAdverseN.Text = "Votre adversaire : " + this.connexion.serveur.SnakeRecu.nameplayer;
                    this.ScoreAdversaire.Text = "Son score actuel : " + this.connexion.serveur.SnakeRecu.Score;
                    this.snakeRecu = null;
                    if (this.connexion.serveur.SnakeRecu != null) this.snakeRecu = new snake(this.connexion.serveur.SnakeRecu);

                }
                else if (this.type == "Client")
                {
                    this.JoueurAdverseN.Text = "Votre adversaire : " + this.connexion.client.nameotherplayer;
                    this.ScoreAdversaire.Text = "Son score actuel : " + this.connexion.client.SnakeRecu.Score;
                    
                    if(this.connexion.client.SnakeRecu != null) this.snakeRecu = new snake(this.connexion.client.SnakeRecu);
                }
                

                if (!this.snake.mordu())
                {
                    //Affichage et gestion de son snake.
                    this.snake.moveSnake();// à voir pour gestion de pomme
                    //this.snake.increaseMoves();

                    //

                    this.printSnake(this.snake, this.snakeRecu, this.pictureList, this.pictureList_other_player);

                    //this.printSnakeRecu(this.snakeRecu, true, this.pictureList_other_player); 

                   //


                    this.pommeManager();
                   
                  
                }
                else
                {
                   //Inutile autant utiliser le bouton snake plutôt rajouter une popup d'avertisesment quand on quitte la partie
                    //je ne tue pas le timer pour qu'on puisse choisir par la suite " quitter partie ou laisser autre jouer ".
                    if(this.FinPartie)
                    {
                    Thread Fin = new Thread(new ThreadStart(Perdu));
                    Fin.Start();
                    Fin.Join();
                    }

                    this.printSnake(this.snake, this.snakeRecu, this.pictureList, this.pictureList_other_player);
                    //this.timer.Stop();
                }
            }
            this.snake.Envoyer = true;
        }
        
        private void Perdu()
        {
            this.FenetrePerdu = new Perdu(this.snake);

            this.FenetrePerdu.ShowDialog();

            this.FinPartie = false;
        }
        


        public void printBarre(Boolean b)
        {
            if (b.Equals(false))//sinon on incremente
            {
                this.BarEventNext.Increment(1);
            }
            else//si c'est vrai alors il a accompli un bonus
            {
                //ne modifie pas la valeurs ici probleme peut être
                this.BarEventNext.Minimum = 0;
                this.BarEventNext.Maximum=bobonus.GetNb_next_Bonus();
                this.BonusOuPas = true;
                this.BarEventNext.Value = 0;
                //MessageBox.Show("Pas mal, continue comme ça!");
                this.bonus.Pictures.Visible = true;
                this.EcranPrincipal.Controls.Add(this.bonus.Pictures);
            }
        }

        public void printSnake(snake Snake, snake Snake1, List<PictureBox> List, List<PictureBox> List1)
        {

            int x;
            try
            {


                if (!snake.mordu())
                {
                    /*snake.ReturnList.ElementAt(i).Visible = false;
                    snake.ReturnList.RemoveAt(i);*/
                    List.ElementAt(0).Visible = false;
                    List.RemoveAt(0);

                    List.ElementAt(List.Count - 1).Load("./../../Ressource/Corps.png");

                    //Puis on affiche les nouvelles
                    x = (Snake.Cords.Count - 1);

                    PictureBox newPict = new PictureBox();
                    newPict.SetBounds(Snake.Cords.ElementAt(x).X, Snake.Cords.ElementAt(x).Y, 10, 10);
                    newPict.Visible = true;
                    if (snake.getDir() == 0)
                    {
                        newPict.Load("./../../Ressource/Tetedroite.png");
                    }
                    else if (snake.getDir() == 1)
                    {
                        newPict.Load("./../../Ressource/Tetegauche.png");
                    }
                    else if (snake.getDir() == 2)
                    {
                        newPict.Load("./../../Ressource/Tetehaut.png");
                    }
                    else if (snake.getDir() == 3)
                    {
                        newPict.Load("./../../Ressource/Tetebas.png");
                    }
                    List.Add(newPict);

                    this.EcranPrincipal.Controls.Add(newPict);


                    //Console.WriteLine("Nb elements list :"+List1.Count);
                }
                   

                    List1.ElementAt(0).Visible = false;
                    List1.RemoveAt(0);
                    //snake1.decreaseMoves();

                    List1.ElementAt(List1.Count - 1).Load("./../../Ressource/corps.png");
                    
                    //Puis on affiche les nouvelles

                    x = (Snake1.Cords.Count - 1);
                    Console.WriteLine("Nb elements snake :" + x);
                    PictureBox newPict1 = new PictureBox(); 
                    newPict1.SetBounds(Snake1.Cords.ElementAt(x).X, Snake1.Cords.ElementAt(x).Y, 10, 10);
                    newPict1.Visible = true;
                    if (snake.getDir() == 0)
                    {
                        newPict1.Load("./../../Ressource/Tetedroite.png");
                    }
                    else if (snake.getDir() == 1)
                    {
                        newPict1.Load("./../../Ressource/Tetegauche.png");
                    }
                    else if (snake.getDir() == 2)
                    {
                        newPict1.Load("./../../Ressource/Tetehaut.png");
                    }
                    else if (snake.getDir() == 3)
                    {
                        newPict1.Load("./../../Ressource/Tetebas.png");
                    } newPict1.Load("./../../Ressource/tete.bmp");
                    List1.Add(newPict1);


                    //  Console.WriteLine("Fait mon snake");
                    this.Ecransecond.Controls.Add(newPict1);


                    //gestion de l'agrandissement du snake recu
                    if (tailleAncienSnake < (this.snakeRecu.Cords.Count - 1))
                    {
                        //blindage au cas ou le snake grandirai + d'une fois entre deux receptions.

                        int nb =(this.snakeRecu.Cords.Count - 1) - tailleAncienSnake ;
                        
                        for (int a = 0; a < nb; a++)
                        {
                            //for(int i=0
                            PictureBox newTete = new PictureBox();
                            newTete.SetBounds(this.snakeRecu.Tete.X, this.snakeRecu.Tete.Y, 10, 10);
                            if (snake.getDir() == 0)
                            {
                                newTete.Load("./../../Ressource/Tetedroite.png");
                            }
                            else if (snake.getDir() == 1)
                            {
                                newTete.Load("./../../Ressource/Tetegauche.png");
                            }
                            else if (snake.getDir() == 2)
                            {
                                newTete.Load("./../../Ressource/Tetehaut.png");
                            }
                            else if (snake.getDir() == 3)
                            {
                                newTete.Load("./../../Ressource/Tetebas.png");
                            }
                            newTete.Visible = true;
                            this.pictureList_other_player.ElementAt(this.pictureList_other_player.Count - 1).Load("./../../Ressource/Corps.png");
                            this.pictureList_other_player.Add(newTete);
                            this.Ecransecond.Controls.Add(newTete);
                            tailleAncienSnake = (this.snakeRecu.Cords.Count - 1);
                        }
                    }

            }
            catch (Exception)
            {
                Console.WriteLine("Affichage Snake Probleme");
            }




        }


        /*  fonction affichant le snake 
            1er argument : snake a afficher
         *  2eme argument : emplacement ou l'afficher. true = ecran secondaire, false = ecran principal
         */
    /*    public void printSnake(snake Snake,Boolean Recus,List<PictureBox> List)
        {
            
                int x;
                int moves=1;
                try
                {
                    if (Snake.Moves > 0)
                    {

                      
                        /*snake.ReturnList.ElementAt(i).Visible = false;
                        snake.ReturnList.RemoveAt(i);*/
        /*               List.ElementAt(0).Visible = false;
                        List.RemoveAt(0);
                        snake.decreaseMoves();

                        List.ElementAt(List.Count - 1).Load("./../../Ressource/corps.bmp");
                        //Puis on affiche les nouvelles
                        x = (Snake.Cords.Count - 1);
                        for (int j = 0; j < moves; j++)
                        {
                            PictureBox newPict = new PictureBox();
                            newPict.SetBounds(Snake.Cords.ElementAt(x + j).X, Snake.Cords.ElementAt(x + j).Y, 10, 10);
                            newPict.Visible = true;
                            newPict.Load("./../../Ressource/tete.bmp");
                            List.Add(newPict);

                           
                            Console.WriteLine("Fait mon snake");
                            this.EcranPrincipal.Controls.Add(newPict);
                            

                        }

                    }
                }
                 catch (Exception)
                {
                 Console.WriteLine("Affichage Snake Probleme");
                }
                
               
                
            
        }
*/
        public void pommeManager()
        {
            if (pomme.coords.Equals(snake.Tete))
            {
                pomme.PommeManger();
                snake.Grown();
                PictureBox newTete = new PictureBox();
                newTete.SetBounds(this.snake.Tete.X, this.snake.Tete.Y, 10, 10);
                if (snake.getDir() == 0)
                {
                    newTete.Load("./../../Ressource/Tetedroite.png");
                }
                else if (snake.getDir() == 1)
                {
                    newTete.Load("./../../Ressource/Tetegauche.png");
                }
                else if (snake.getDir() == 2)
                {
                    newTete.Load("./../../Ressource/Tetehaut.png");
                }
                else if (snake.getDir() == 3)
                {
                    newTete.Load("./../../Ressource/Tetebas.png");
                }
                newTete.Visible = true;
                this.pictureList.ElementAt(this.pictureList.Count - 1).Load("./../../Ressource/Corps.png");
                this.pictureList.Add(newTete);
                this.EcranPrincipal.Controls.Add(newTete);
                printBarre(bobonus.IncrementeBonus());
                
               
                this.EcranPrincipal.Controls.Add(this.pomme.Pictures);
                this.snake.Score++;
                //this.score++;
                this.Monscore.Text = "Votre Score : " + (this.snake.Score);
            }

            if (bonus.coords.Equals(snake.Tete))
            {
                
                snake.Grown();
                PictureBox newTete = new PictureBox();
                newTete.SetBounds(this.snake.Tete.X, this.snake.Tete.Y, 10, 10);
                if (snake.getDir() == 0)
                {
                    newTete.Load("./../../Ressource/Tetedroite.png");
                }
                else if (snake.getDir() == 1)
                {
                    newTete.Load("./../../Ressource/Tetegauche.png");
                }
                else if (snake.getDir() == 2)
                {
                    newTete.Load("./../../Ressource/Tetehaut.png");
                }
                else if (snake.getDir() == 3)
                {
                    newTete.Load("./../../Ressource/Tetebas.png");
                }
                newTete.Visible = true;
                this.pictureList.ElementAt(this.pictureList.Count - 1).Load("./../../Ressource/Corps.png");
                this.pictureList.Add(newTete);
                this.EcranPrincipal.Controls.Add(newTete);
                
                this.bonus.BonusManger();//apparait à la suite de cette instruction
               // this.bonus.Pictures.Visible = false;
                this.BonusOuPas = false;
                //this.score += 5;
                this.snake.Score += 5;
                //this.score += 5;
                this.Monscore.Text = "Votre Score : " + this.snake.Score;
            }

           
        }

        

        //partie permettant la gestion des fleches
        //permettra la gestion des touches par exemple -> alors faire etc..
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            if (this.move == false)
            {
                this.move = true;
                switch (keyData)
                {
                    case Keys.Right:
                        this.snake.changedirect(Keys.Right);
                        return true;

                    case Keys.Left: this.snake.changedirect(Keys.Left);
                        return true;

                    case Keys.Up: this.snake.changedirect(Keys.Up);
                        return true;

                    case Keys.Down: this.snake.changedirect(Keys.Down);
                        return true;

                    default: return base.ProcessCmdKey(ref msg, keyData);

                }
            }
            else
            {
                return true;
            }
        }
        

        private void quitterToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (this.type != null)//manière peut propre pour évité un bug 
            {
                this.connexion.EndConnexion();
            }
            this.timer.Stop();
            this.Close();

        }

        private void simpleToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Snake.Vue.FormConnexion SaisirNom = new Snake.Vue.FormConnexion(this);
            SaisirNom.ShowDialog();
            this.Jnom.Text = "Votre pseudo : " + this.NomJoueur;
            this.panel2.Visible = true;
        }

        private void multiToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Snake.Vue.FormConnexion SaisirNom = new Snake.Vue.FormConnexion(this);
            SaisirNom.ShowDialog();
            this.Jnom.Text = "Votre pseudo : " + this.NomJoueur;

            this.panel2.Visible = true;
            this.panel1.Visible = true;
            this.panel3.Visible = true;
        }

        private void PartieSimple_Click(object sender, EventArgs e)
        {
            this.PartieSimple.Visible = false;
            this.PartieMulti.Visible = false;

            this.Jnom.Text = "Votre pseudo : " + this.NomJoueur;
            this.panel2.Visible = true;
        }

        private void PartieMulti_Click(object sender, EventArgs e)
        {
            //effet visuel
            this.PartieSimple.Visible = false;
            this.PartieMulti.Visible = false;

            //Page d'information avant lancement
            Snake.Vue.FormConnexion SaisirNom = new Snake.Vue.FormConnexion(this);
            SaisirNom.ShowDialog();
           
            //utilisation des mutex pour la synchronisation
            
            //nom du joueur
            this.snake.nameplayer = this.NomJoueur;
            this.Jnom.Text = "Votre pseudo : " + this.NomJoueur;

            //etablissement des connexions ( soit serveur, soit client )
            connexion = new Connexion(this.type);

            //on lance soit le serveur, soit le client.
               if (this.type == "Client")//envoyer les nom mais il faudrai bloqué
               {//la partie avant que le jeux se lance ... , genre attente de joueur.
                   this.connexion.Client(this.Ip);
                   this.connexion.client.Envois(this.snake);
                   this.connexion.client.Reception();
                   
                   //tjr technique de merde à revoir probablement avec un synchronized ou autre je vous laisse le choix
                   while (this.connexion.client.Recu != true)
                   {

                   }

                   this.initialisation_snake(this.connexion.client.SnakeRecu, true);
                 /*  this.snake.ReturnList = new List<PictureBox>();
                   int count = 1;
                   foreach (Point point in this.connexion.client.SnakeRecu.Cords)
                   {
                       PictureBox picture = new PictureBox();
                       picture.SetBounds(this.connexion.client.SnakeRecu.Cords.ElementAt(count - 1).X, this.connexion.client.SnakeRecu.Cords.ElementAt(count - 1).Y, 10, 10);
                       picture.Visible = true;

                       if (count == this.connexion.client.SnakeRecu.Size)
                       {
                           picture.Load("./../../Ressource/Tete.bmp");
                       }
                       else
                       {
                           picture.Load("./../../Ressource/Corps.bmp");
                       }
                       this.EcranSecond.Controls.Add(picture);
                       this.pictureList_other_player.Add(picture);
                       count++;
                   }
                   */
               }
               else if (this.type == "Serveur")
               {
                   //lance le serveur.
                   this.connexion.Serveur(this.snake);

                   Thread attente = new Thread(new ThreadStart(Attente));
                   attente.Start();//lancement thread
                    //technique de merde à modifier ...
                   while (this.connexion.serveur.clientconnected != true)
                   {
                       
                   }

                   attente.Abort();//fin de thread
                   this.initialisation_snake(this.connexion.serveur.SnakeRecu, true);
                   //Premier affichage - probleme du coup avec la fonction d'affichage qui utilise ces donnée, le snake
                   //de l'autre joueur ne posséde pas les même donnée obligatoirement.
                   //On cree la liste des pictures box affichées a l'écran

                   
                   /*int count = 1;
                   foreach (Point point in this.connexion.serveur.SnakeRecu.Cords)
                   {
                       PictureBox picture = new PictureBox();
                       picture.SetBounds(this.connexion.serveur.SnakeRecu.Cords.ElementAt(count - 1).X, this.connexion.serveur.SnakeRecu.Cords.ElementAt(count - 1).Y, 10, 10);
                       picture.Visible = true;

                       if (count == this.connexion.serveur.SnakeRecu.Size)
                       {
                           picture.Load("./../../Ressource/Tete.bmp");
                       }
                       else
                       {
                           picture.Load("./../../Ressource/Corps.bmp");
                       }
                       this.EcranSecond.Controls.Add(picture);
                       this.pictureList_other_player.Add(picture);
                       count++;
                   }*/
               
               }
             
            
            this.panel2.Visible = true;
            this.panel1.Visible = true;
            this.panel3.Visible = true;
        }

        private void Attente()
        {
            WaitPlayeur Wait = new WaitPlayeur();
            Wait.ShowDialog();
            Wait.Visible = true;
        }

        private void Quitter_Click(object sender, EventArgs e)
        {
            if (this.type != null)//manière peut propre pour évité un bug 
            {
                this.connexion.EndConnexion();//ceci doit arrêté tous les threads ayant pu être lancer et ainsi que les connexion
                    //néanmoins je pense qu'un message doit d'abord être envoyer au client / serveur pour le prevenir aussi sinon probléme de l'autre coté 
                //puiqsue la connexion n'est pas "close"
            }
            this.timer.Stop();
            Close();
        }

      
       


        public string Nom
        {
            get { return NomJoueur; }
            set { NomJoueur = value; }
        }

        private void EcranPrincipal_Paint(object sender, PaintEventArgs e)
        {

        }

     

    }
}
